local atan = math.atan
local sin = math.sin
local cos = math.cos
local rad = math.rad
local sqrt = math.sqrt
local deg = math.deg
require("fishenum")

local fish = {}

--[[ 暂时缓存可能用到的全数据，如果后期数据量太大，再改为读配置
	config = {
		-- Id = 0,	-- 编号，创建实体时生成随机不重复的值
		Type = 0,	-- 类型，通过配置可以取名字，描述等信息
		R = 0,		-- 半径值，目前判定为圆形
		PosX = 0,	-- 圆心位置X（默认路径起点）
		PosY = 0,	-- 圆心位置Y（默认路径起点）
		Angle = 0,	-- 转动角度
		Stat = 0,	-- 状态，-1 死亡 1 存活
		Level = 0,	-- 等级
		Speed = 0,	-- 移动速度
		Point = 0,	-- 价值分数
		HP = 0,		-- 血量
		HPmax = 0,	-- 最大血量
		HuntedWeight = 0,	-- 被捕权重
		Positions	-- 移动轨迹点
		PosIdx = 0,	-- 当前起点索引
		DeadType = 0,		-- 死亡类型(Stat等于-1时有效) 1 击中死亡  2 路径完成死亡 
		DropId = 0,	-- 掉落id
		Turns = 0,	-- 轨迹循环次数，次数用完鱼消失（暂未实现）
		OffsetX = 0,-- 坐标偏移X（批量生产鱼，以第一条鱼为原点）
		OffsetY = 0,-- 坐标偏移Y（批量生产鱼，以第一条鱼为原点）
	} 
--]]
local function init(entity, dinit)
	entity.Id 		= dinit.Id
	entity.Type 	= dinit.Type
	entity.R 		= dinit.R
	entity.Angle 	= dinit.Angle
	entity.Stat 	= dinit.Stat or EEntityStat.ALIVE
	entity.Level 	= dinit.Level
	entity.Speed 	= dinit.Speed
	entity.Point	= dinit.Point
	entity.HP 		= dinit.HP or 1
	entity.HPmax 	= dinit.HPmax or 1
	entity.HuntedWeight = dinit.HuntedWeight
	entity.DeadType	= -1
	entity.Ts 		= dinit.Ts
	entity.Group	= dinit.Group
	entity.DropId	= dinit.DropId
	entity.ComboHit	= {}
	
	entity.Positions= dinit.Positions
	entity.PosIdx	= dinit.PosIndex or 1
	entity.PosX 	= 0		-- dinit.PosX or entity.Positions[1][1]
	entity.PosY 	= 0 	-- dinit.PosY or entity.Positions[1][2]
	entity.OffsetX	= dinit.OffsetX or 0
	entity.OffsetY  = dinit.OffsetY or 0
end

function fish:new(s2csync, dinit, nosync, obj)
	local entity = obj or {}
	init(entity, dinit)
	entity.s2csync = s2csync

	setmetatable(entity, self)
	self.__index = self
	if not nosync then
		entity:sync()
	end
	return entity
end

-- ex: 有些鱼不需要单独同步，比如说群体死亡的时候。
function fish:die(type, ex)
	self.HP = 0
	self.Speed = 0
	self.Stat = EEntityStat.DEAD
	self.ComboHit = {}
	self.DeadType = type or self.DeadType
	if not ex then
		self:sync()
	end
end

function fish:check_edge(screen)
	if self.PosIdx == 1 then return false end
	if self.PosX <= -self.R*2 or self.PosX >= screen.Width + self.R*2 then
		self:die()
		return true
	elseif self.PosY <= -self.R*2 or self.PosY >= screen.Height + self.R*2 then
		self:die()
		return true
	end
	return false
end

function fish:move(screen)
	if self.Speed == 0 or self.Stat == EEntityStat.DEAD then
		return
	end
	local speed = self.Speed
	local angle = self.Angle
	self.PosX = self.PosX + speed*sin(rad(angle))
	self.PosY = self.PosY + speed*cos(rad(angle))

	local idx = self.PosIdx
	local point = self.Positions[idx]
	local len = sqrt((self.PosX - point[1])^2 + (self.PosY - point[2])^2)
	-- print("fish:move check:", self.PosX, self.PosY, self.Angle, len, self.Speed)
	if len <= self.Speed then
		if self:check_edge(screen) then
			return
		end
		self.PosX = point[1]
		self.PosY = point[2]
		self:move_to_position()
		return
	end

	-- self:sync()	-- 同步是不可能同步的，这辈子都不可能同步
end

function fish:move_to_position()
	self.PosIdx = self.PosIdx + 1
	local idx = self.PosIdx
	if not self.Positions[idx] then
		self.PosIdx = 1
		idx = 1
	end
	local point = self.Positions[idx]
	if not point then
		print("move to position error: no point")
		return
	end
	-- 以自身为坐标原点，向上为0度，根据点的相对位置计算角度
	local k = 0	-- 斜率，这里保证为正值
	local offset = 0
	if point[2] == self.PosY then		-- 水平移动
		if point[1] == self.PosX then	-- 如果出现这种情况会导致物体停在原地一帧
			k = 0
			offset = 0
		elseif point[1] > self.PosX then
			k = 0
			offset = 90
		elseif point[1] < self.PosX then
			k = 0
			offset = 270
		end
	elseif point[2] > self.PosY then
		if point[1] == self.PosX then	-- 向上移动
			k = 0
			offset = 0
		elseif point[1] > self.PosX then
			k = (point[1] - self.PosX)/(point[2] - self.PosY)	-- 第一象限
			offset = 0
		elseif point[1] < self.PosX then
			k = (point[2] - self.PosY)/(self.PosX - point[1])	-- 第四象限
			offset = 270
		end
	else
		if point[1] == self.PosX then	-- 向下移动
			k = 0
			offset = 180
		elseif point[1] > self.PosX then
			k = (self.PosY - point[2])/(point[1] - self.PosX)	-- 第二象限
			offset = 90
		else
			k = (self.PosX - point[1])/(self.PosY - point[2])	-- 第三象限
			offset = 180
		end
	end
	if point[3] then
		self:set_speed(point[3])
	end
	local angle = deg(atan(k)) + offset
	self:turn(angle)
end

function fish:turn(angle)
	self.Angle = angle
	self:sync()
end

function fish:set_speed(speed)
	if speed < 0 then return end
	self.Speed = speed
end

function fish:hunted(bullet)
	self:die(bullet.Rid)
end

function fish:attacked(bullet)
	local id = bullet.Launcher.Id
	self.ComboHit[id] = (self.ComboHit[id] or 0) + 1
	self.HP = self.HP - bullet.Damage
	if self.HP < 0 then
		self.HP = 0
		-- self:die()
	-- else
		-- self:sync()
	end

	bullet:die()
end

function fish:get_combohit(bullet)
	local id = bullet.Launcher.Id
	return self.ComboHit[id] or 0
end

function fish:reset_combohit(launcher)
	if self.ComboHit[launcher.Id] then
		self.ComboHit[launcher.Id] = nil
	end
end

function fish:sync()
	if self.s2csync then
		self:s2csync()
	end
end

return fish
